/*
 * Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

#ifndef GC_TINY_FL_H
#define GC_TINY_FL_H

/*
 * Constants and data structures for "tiny" free lists.
 * These are used for thread-local allocation and inlined allocators.
 * Each global free list also essentially starts with one of these.
 * However, global free lists are known to the collector.
 * "Tiny" free lists are basically private to the client.
 * Their contents are viewed as "in use" and marked accordingly by the
 * core of the collector.  Note that inlined code might know about the
 * layout of these and the constants involved.  Thus any change here
 * may invalidate clients, and such changes should be avoided.
 * Hence we keep this as simple as possible.
 */

/*
 * We always set `GC_GRANULE_BYTES` to twice the length of a pointer.
 * This means that all allocation requests are rounded up to the next
 * multiple of 16 on 64-bit architectures or 8 on 32-bit architectures.
 * This appears to be a reasonable compromise between fragmentation
 * overhead and space usage for mark bits (usually mark bytes).
 * On many 64-bit architectures some memory references require 16-byte
 * alignment, making this necessary anyway.  For a few 32-bit
 * architectures (e.g. i686), we may also need 16-byte alignment for
 * certain memory references.  But currently that does not seem to be
 * the default for all conventional `malloc` implementations, so we
 * ignore that problem.
 * It would always be safe, and often useful, to be able to allocate
 * very small objects with smaller alignment.  But that would cost us
 * mark bit space, so we no longer do so.
 * `GC_GRANULE_BYTES` should not be overridden in any instances of the
 * collector library that may be shared between applications, since it
 * affects the ABI (application binary interface) to the library.
 */
#if defined(CPPCHECK) && GC_GRANULE_BYTES == 1
#  undef GC_GRANULE_BYTES
#endif
#ifdef GC_GRANULE_BYTES
#  define GC_GRANULE_PTRS (GC_GRANULE_BYTES / GC_SIZEOF_PTR)
#else
#  define GC_GRANULE_PTRS 2 /*< in pointers */
#  define GC_GRANULE_BYTES (GC_GRANULE_PTRS * GC_SIZEOF_PTR)
#endif /* !GC_GRANULE_BYTES */

/** Convert size in pointers to that in granules. */
#define GC_PTRS_TO_GRANULES(n) ((n) / GC_GRANULE_PTRS)

/**
 * Convert size in pointers to that in granules, but rounding up the
 * result.
 */
#define GC_PTRS_TO_WHOLE_GRANULES(n) \
  GC_PTRS_TO_GRANULES((n) + GC_GRANULE_PTRS - 1)

/*
 * A "tiny" free-list header contains `GC_TINY_FREELISTS` pointers to
 * singly-linked lists of objects of different sizes, the `i`-th one
 * containing objects of `i` granules in size.  Note that there is
 * a list of size zero objects.
 */
#ifndef GC_TINY_FREELISTS
#  if GC_GRANULE_BYTES >= 16
#    define GC_TINY_FREELISTS 25
#  else
#    define GC_TINY_FREELISTS 33 /*< up to and including 256 bytes */
#  endif
#endif /* !GC_TINY_FREELISTS */

/*
 * The `i`-th free list corresponds to size `i * GC_GRANULE_BYTES`.
 * Internally to the collector, the index `i` can be computed with
 * `ALLOC_REQUEST_GRANS()`.  The latter also depends on the values
 * returned by `GC_get_dont_add_byte_at_end()` and
 * `GC_get_all_interior_pointers()`.
 */

/**
 * Convert a free-list index to the actual size of objects on that list,
 * including extra space we added.  Not an inverse of the above.
 */
#define GC_RAW_BYTES_FROM_INDEX(i) (GC_GRANULE_BYTES * (i))

/* Deprecated.  Use `GC_GRANULE_PTRS` instead. */
#undef GC_GRANULE_WORDS
#define GC_GRANULE_WORDS GC_GRANULE_PTRS

/* Deprecated.  Use `GC_PTRS_TO_GRANULES()` instead. */
#define GC_WORDS_TO_GRANULES(n) GC_PTRS_TO_GRANULES(n)

/* Deprecated. */
#define GC_WORDS_TO_WHOLE_GRANULES(n) GC_PTRS_TO_WHOLE_GRANULES(n)

#endif /* GC_TINY_FL_H */
